﻿using System;
using System.Timers;
using System.Windows.Forms;
using System.IO;
using System.Xml;
using ClassLibrary.Communication;
using ClassLibrary.SignalType;
using ClassLibrary;

namespace Client
    
{
    /// <summary>
    /// @Author Mateusz Lipiński
    /// Client
    /// </summary>
    public partial class Client : Form
    {
        // --- Timer związany z wysyłaniem danych w pętli
        private readonly System.Timers.Timer _timer = new System.Timers.Timer(500);

       

        private DataPackage _dataToSend;
        readonly CommunicationService _communicationService;
        readonly Port port;
        // --- Parametry z pliku konfiguracyjnego
        private string _remoteUsername;
        private string _nodeId;
        private string _clientName;
        private string _cloudHost;
        private string _cloudPort;
        private CPCC CallController;
        private PacketController PacketController;

        public string _ClientName
        {
            get { return _clientName; }
            set { _clientName = value; }
        }

        public string _NodeId
        {
            get { return _nodeId; }
            set { _nodeId = value; }
        }
        /// <summary>
        /// Konstruktor klienta
        /// </summary>
        public Client()
        {
            CallController = new CPCC(this);
            PacketController = new PacketController(CallController);
            CallController.Pc = PacketController;
            

            InitializeComponent();
            _timer.Elapsed += Send;
            _communicationService = CommunicationService.GetInstance();
            port = _communicationService.SetupPorts(1)[0];
            port.DataReceived += HandleEvents;

            textBox2.Enabled = false;
            groupBox2.Enabled = false;

            var args = Environment.GetCommandLineArgs();
            if (args.Length > 1)
            {

                LoadConfig(File.OpenRead(args[1]));
            }

           // PacketController = new PacketController();
          //  PacketController.Log += new PacketController.LogEventHandler(WriteLine);
           // CallController = new CPCC(this, PacketController);
        }
        /// <summary>
        /// Metoda odpowiedziala za obsłużenie zdarzenia związanego 
        /// z nadejściem danych
        /// </summary>
        /// <param name="sender">Port na który przyszły dane</param>
        /// <param name="networkEventType">Zdarzenie</param>
        void HandleEvents(object sender, EventType networkEventType)
        {
            HandleDataReceivedOnPort((Port)sender);
        }

        private delegate void UpdateUiDelegate(Port port);
        void HandleDataReceivedOnPort(Port port)
        {

            listBox1.Invoke(new UpdateUiDelegate(UpdateListBox), port);
        }
        /// <summary>
        /// Metoda odpowiedzialna za dodawanie tekstu otrzymanego od innego klienta.
        /// </summary>
        /// <param name="port">Port na który przyszły dane</param>

        private void UpdateListBox(Port port)
        {
            var dataReceived = (DataPackage)port.Read();
            listBox1.Items.Add(_remoteUsername + " " + "[" + DateTime.Now + "]" + " " + dataReceived.Data);
        }

         ///<summary>
        /// Zamknięcie aplikacji.
        /// </summary>
        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Close();
        }
        /// <summary>
        /// Załadowanie pliku konfiguracyjnego w formacie XML.
        /// </summary>
        private void openToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Stream myStream = null;
            OpenFileDialog openFileDialog1 = new OpenFileDialog();

            openFileDialog1.InitialDirectory = "c:\\";
            openFileDialog1.Filter = "(*.xml)|*.xml";
            openFileDialog1.FilterIndex = 2;
            openFileDialog1.RestoreDirectory = true;

            if (openFileDialog1.ShowDialog() == DialogResult.OK)
            {
                try
                {

                    if ((myStream = openFileDialog1.OpenFile()) != null)
                    {
                        using (myStream)
                        {
                            LoadConfig(myStream);
                        }
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show("Error: Could not read file from disk. Original error: " + ex.Message);
                }
            }

        }
        /// <summary>
        /// Metoda odpoiwedzialna za załadowanie i przypisanie odpowiednim zmiennymn
        /// wartości zawartych w pliku konfiguracyjnym.
        /// </summary>
        /// <param name="myStream">Strumień z plikiem konfiguracyjnym</param>

        private void LoadConfig(Stream myStream)
        {
            XmlDocument doc = new XmlDocument();
            XmlReaderSettings settings = new XmlReaderSettings();
            settings.ConformanceLevel = ConformanceLevel.Auto;
            settings.IgnoreWhitespace = true;
            settings.IgnoreComments = true;

            doc.Load(myStream);
            XmlNodeReader noder = new XmlNodeReader(doc);
            XmlReader reader = XmlReader.Create(noder, settings);
            while (reader.Read())
            {
                if (reader.NodeType == XmlNodeType.Element)
                {
                    if (reader.Name == "NodeId")
                    {
                        reader.Read();
                        _nodeId = reader.Value;
                    }

                    if (reader.Name == "ClientName")
                    {
                        reader.Read();
                        _clientName = reader.Value;
                    }

                    if (reader.Name == "RemoteUsername")
                    {
                        reader.Read();
                        _remoteUsername = reader.Value;
                    }

                    if (reader.Name == "CloudHost")
                    {
                        reader.Read();
                        _cloudHost = reader.Value;
                    }

                    if (reader.Name == "CloudPort")
                    {
                        reader.Read();
                        _cloudPort = reader.Value;
                    }

                }
            }

            textBox2.Enabled = true;
            groupBox2.Enabled = true;
            _communicationService.Connect(_cloudHost, System.Convert.ToInt16(_cloudPort));
            _communicationService.Login(_nodeId);
            this.Text = _nodeId;
        }

        private void Client_Load(object sender, EventArgs e)
        {

        }
        /// <summary>
        /// Wysłanie danych do innego klienta.
        /// </summary>
        private void button1_Click(object sender, EventArgs e)
        {
            _dataToSend = new DataPackage(textBox2.Text);
            port.Send(_dataToSend);
            textBox2.Clear();
            listBox1.Items.Add(_clientName + " " + "[" + DateTime.Now + "]" + " " + _dataToSend.Data);
        }

        private void textBox2_TextChanged(object sender, EventArgs e)
        {


        }

        private void groupBox2_Enter(object sender, EventArgs e)
        {

        }

        private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
        {

        }
        /// <summary>
        /// Czyszczenie okna rozmowy.
        /// </summary>
        private void ClearButton_Click(object sender, EventArgs e)
        {
            listBox1.Items.Clear();
        }

        private void menuStrip1_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
        {

        }

        /// <summary>
        /// Wysyłanie danych w pętli
        /// </summary>

        private void button1_Click_1(object sender, EventArgs e)
        {
            if (_timer.Enabled)
            {
                _timer.Stop();
            }
            else
            {
                _timer.Start();
            }

        }
        /// <summary>
        /// Metoda odpowiedzialna za wysyłanie danych w pętli.
        /// </summary>
        /// <param name="elapsedEventArgs">Zdarzenie związane z wysyłaniem danych w pętli</param>
        private void Send(object sender, ElapsedEventArgs elapsedEventArgs)
        {
            _dataToSend = new DataPackage(textBox2.Text);
            port.Send(_dataToSend);
            listBox1.Items.Add(_clientName + " " + "[" + DateTime.Now + "]" + " " + _dataToSend.Data);
        }

        public void WriteLine(string one)
        {
            this.Invoke((MethodInvoker)delegate
            {
                string Time = DateTime.Now.ToString("[HH:mm:ss tt] ");
            });
        }

        private void button4_Click(object sender, EventArgs e)
        {
            CallController.CallRequest(_nodeId, textBox1.Text);
        }
    }
}
